package org.jflame.auth.session.springsession;

import org.jflame.auth.context.UserContext;
import org.jflame.auth.session.SessionInfo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;

class SpringSessionBackedSessionInfo<S extends Session> extends SessionInfo {

    private static final long serialVersionUID = -1971005296593625793L;

    static final String EXPIRED_ATTR = SpringSessionBackedSessionInfo.class.getName() + ".EXPIRED";

    private final Logger logger = LoggerFactory.getLogger(SpringSessionBackedSessionInfo.class);

    private final SessionRepository<S> sessionRepository;

    SpringSessionBackedSessionInfo(S session, SessionRepository<S> sessionRepository) {
        super(resolvePrincipal(session), session.getId(), session.getLastAccessedTime()
                .toEpochMilli());
        this.sessionRepository = sessionRepository;
        Boolean expired = session.getAttribute(EXPIRED_ATTR);
        if (Boolean.TRUE.equals(expired)) {
            super.expireNow();
        }
    }

    private static String resolvePrincipal(Session session) {
        String principalName = session.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
        if (principalName != null) {
            return principalName;
        }
        UserContext securityContext = session.getAttribute(UserContext.CONTEXT_KEY);
        if (securityContext != null && securityContext.getUser() != null) {
            return securityContext.getUser()
                    .getUserName();
        }
        return "";
    }

    @Override
    public void expireNow() {
        if (logger.isDebugEnabled()) {
            logger.debug("Expiring session " + getSessionId() + " for user '" + getPrincipal()
                    + "', presumably because maximum allowed concurrent " + "sessions was exceeded");
        }
        super.expireNow();
        S session = this.sessionRepository.findById(getSessionId());
        if (session != null) {
            session.setAttribute(EXPIRED_ATTR, Boolean.TRUE);
            this.sessionRepository.save(session);
        } else {
            logger.info("Could not find Session with id " + getSessionId() + " to mark as expired");
        }
    }

}
